package metodos;

import Compilador.Plantilla;
import com.sun.org.apache.bcel.internal.generic.BREAKPOINT;
import datos.Datos;
import datos.Regla;
import java.util.ArrayList;
import javax.print.attribute.standard.Finishings;
import javax.swing.plaf.LabelUI;

public class Asociacion extends Metodo {

    String Reglas;
    String ReglasProlog;
    String filejava;
    Datos datos;
    String clase;
    ArrayList< String> Items;
    ArrayList< ArrayList<String>> ItemsGroup;
    ArrayList<ArrayList<String>> lista;
    int cobertura;
    float precision;
    int iteracionSet; //numero de ItemSet's
    int numGrupo;
    public ArrayList< String> AuxCombinacion = new ArrayList<String>();

    public Asociacion(Datos datos,int cober,float preci) {
        this.datos = datos;
        this.clase = datos.getNombreClase();
        ItemsGroup = new ArrayList<ArrayList<String>>();
        cobertura = cober;
        precision = preci/100;
        iteracionSet = 0;
        Reglas = "";
        filejava = "";
        numGrupo = 0;
        for (int i = 0; i < datos.getTitulos().length; i++) {
            if (clase.equals(datos.getTitulos()[i])) {
                numGrupo = i;
            }
        }

        lista = datos.getLista();
        Items = generarItems(lista);
    }

    @Override
    public void Calcular() {
        System.out.println("\nCalcular\n\n");


        ArrayList< String> ItemsConCobertura = new ArrayList<String>();
        ArrayList<String> ItemsVariables = new ArrayList<String>();
        for (int i = 0; i < Items.size(); i++) {
            ItemsVariables.add(Items.get(i));
        }



        //////////////PROLOG///////////////////


        //Campos seleccionados en la UI y su valores en la DB incluida la clase
        String camposConClase[] = formatear(datos.getTitulos());
        //Valores de esos campos

        //Un nuevo vector que almacenará los campos sin la clase
        String campos[] = new String[camposConClase.length - 1];
        ArrayList<ArrayList<String>> valoresCampos = datos.getPosiblesValores();

        int indiceCampo = 0;

        //Quitamos la clase de los campos
        for (int l = 0; l < camposConClase.length; l++) {

            if (!camposConClase[l].equals(formatear(datos.getNombreClase()))) {
                campos[indiceCampo++] = camposConClase[l];
            } else {
                valoresCampos.remove(l);
            }


        }


        char variables[] = new char[campos.length];

        //Sacamos la cantidad de variables necesarias del abecedario en MAYÚSCULAS
        for (int i = 65; i < 65 + campos.length; i++) {

            variables[i - 65] = (char) i;

        }

        //La variable que sirve para guardar el resultado en PROLOG
        char variableFinal = (char) ((char) variables[variables.length - 1] + 1);


        ReglasProlog = "";

        //Declaramos las proposiciones y sus posibles valores
        for (int i = 0; i < campos.length; i++) {

            for (int j = 0; j < valoresCampos.get(i).size(); j++) {
                ReglasProlog += formatear(campos[i]) + "(" + formatear(valoresCampos.get(i).get(j)) + ").\n";
            }

            ReglasProlog += "\n";

        }

        //Declaramos la proposición de la clase
        ReglasProlog += formatear(datos.getNombreClase()) + "(";




        //Letras
        for (int i = 0; i < campos.length; i++) {

            ReglasProlog += variables[i] + "";

            if (i != variables.length - 1) {
                ReglasProlog += ", ";
            } else {
                ReglasProlog += ", " + variableFinal + ") :- ";
            }
        }


        //Declaraciones
        for (int i = 0; i < campos.length; i++) {

            ReglasProlog += formatear(campos[i]) + "(" + variables[i] + "), ";

        }

        //////////////PROLOG///////////////////




        for (iteracionSet = 1; iteracionSet < ItemsGroup.size(); iteracionSet++) { // Número de ItemSet.

            for (int j = 0; j < ItemsVariables.size(); j++) {

                String items = ItemsVariables.get(j);
                int cuantos = buscarItems(items);

//                System.out.print("Existe " + items+ ": " + cuantos);
                if (cuantos < cobertura) {
                }//System.out.print(" - NO COBERTURA");
                else {
                    ItemsConCobertura.add(items);
                    String[] combo = items.split(",");

                    for (int k = 0; k < combo.length; k++) {

                        ArrayList<String> primario = ListaCombinaciones(combo, combo.length, k);

                        String muestra = "*";
                        ArrayList< String> reglasShow = new ArrayList<String>();
                        for (int l = 0; l < primario.size(); l++) {
                            if (!perteneceEleccion(primario.get(l).split(","))) {
                                continue;
                            }

                            float p = precision(primario.get(l), k); //Trae Precision

                            if (k != 0) {
                                muestra = Integer.toString(l + 1);
                            }

                            if (p < precision) {
                            }//System.out.print("\n" + muestra + ". " + primario.get(l) + "_" + k + " - NO PRECISION");
                            else {
//                                System.out.print("\n" + muestra + ". " + primario.get(l)+ "_" + k + " - SI precision");

                                //Las reglas
                                String ReglasAux = "";
                                String javaAux = "";
                                String ReglasAuxProlog = "";


                                String[] fila = primario.get(l).split(",");

                                String show = "";
                                String showPrint = "SI ";
                                String javashow = "if(";
                                String showPrintProlog = "(";
                                for (int m = 0; m < fila.length; m++) {
                                    if (m < k) {

                                        int numG = NumGrupo(fila[m]);

                                        String nombreGrupo = datos.getTitulos()[numG];
                                        show += fila[m];
                                        showPrint += nombreGrupo + "=" + fila[m];
                                        javashow += "(" + '"' + fila[m] + '"' + ".equalsIgnoreCase(" + nombreGrupo + "))";
                                        showPrintProlog += variables[this.indice(campos, formatear(nombreGrupo))] + "='" + formatear(fila[m]) + "'";

                                        if (m < k - 1) {
                                            showPrint += " && ";
                                            javashow += " && ";
                                            showPrintProlog += ", ";
                                            show += ",";
                                        }
                                    } else if (m == k) {
                                        String nombreGrupo = datos.getTitulos()[ NumGrupo(fila[m])];
                                        ReglasAux += showPrint + "  ==>  " + nombreGrupo + "=" + fila[m];
                                        javaAux += javashow + "){label.setText(" + '"' + fila[m] + '"' + ");}";
                                        ReglasAuxProlog += showPrintProlog + ")->" + variableFinal + "='" + formatear(fila[m]) + "';";


                                    } else if (m > k) {
                                        String nombreGrupo = datos.getTitulos()[ NumGrupo(fila[m])];
                                        ReglasAux += " && " + nombreGrupo + "=" + fila[m];
                                        javaAux += " && (" + '"' + fila[m] + '"' + ".equalsIgnoreCase(" + nombreGrupo + "))";
                                        ReglasAuxProlog += ", " + nombreGrupo + "='" + formatear(fila[m]) + "'";
                                    }
                                }
                                ReglasAux += "\n";
                                javaAux += "\n";
                                if (!seEncuentra(show, reglasShow)) {
                                    Reglas += ReglasAux;
                                    filejava += javaAux;
                                    ReglasProlog += ReglasAuxProlog;
                                }

                                reglasShow.add(show);
                            }
                        }


                    }
                }
//                System.out.println("\n");
            }
            //******************************************************+
            // Prepara siguiente ItemSet
//            System.out.println("\nIteracionSet: " + iteracionSet + " de " + ItemsGroup.size()); 
//            if ( iteracionSet == ItemsGroup.size() - 1) break;

            int tamanoOriginal = ItemsConCobertura.size();
            ItemsVariables.clear();

            for (int i = 0; i < tamanoOriginal; i++) {
                String valorC = ItemsConCobertura.get(i);

                for (int j = 0; j < Items.size(); j++) {
                    String valor = Items.get(j);
//                    System.out.println("Pegar " + valorC + " -> " + valor);

                    boolean found = false;
                    String[] mientras = valorC.split(",");
                    for (int k = 0; k < mientras.length; k++) {
                        if (mientras[k].equals(valor)) {
                            found = true;
                            break;
                        }
                    }

                    if (found) {
                        continue;
                    }

                    if (mismoGrupo(valorC, valor)) {
                        continue;
                    }

//                    if( RepiteItems(ItemsVariables, valorC) ) continue;

//                    for (int k = 0; k <= i; k++) {
//                        String[] g = ItemsConCobertura.get(k).split(",");
//                        System.out.println("Grupo: " + ItemsConCobertura.get(k));
//                        for (int l = 0; l < g.length; l++) //g.lenght
//                            if( valor.equals(g[l]) ) {
//                                found = true; break; 
//                            }
//                        
//                        if( found ) break;
//                    }
//                    if(found) continue;

                    String aux = valorC + "," + valor;

//                    System.out.println("Analiza : " + ItemsVariables + "\n...con " + valorC);
                    if (RepiteItems(ItemsVariables, aux)) {
                        continue;
                    }
//                    System.out.println("Pasó !!\n");

                    valorC += "," + valor;
                    ItemsVariables.add(valorC);

                    valorC = ItemsConCobertura.get(i);
                }

            }

//            for (int i = 0; i < tamanoOriginal; i++) ItemsVariables.remove(0);
//            System.out.println("\nItemsVariables: \n");
//            for (int i = 0; i < ItemsVariables.size(); i++)
//                System.out.println(ItemsVariables.get(i));

            ItemsConCobertura.clear();
//            if(iteracionSet == 3 ) iteracionSet = ItemsGroup.size();
        }

        Reglas += "\n\n\nCobertura = " + cobertura + "\nPrecision = " + (precision * 100) + "%\n";

    }

    private boolean seEncuentra(String show, ArrayList<String> reglasShow) {

        boolean retorno = false;
        String[] buscar = show.split(",");

        for (int i = 0; i < reglasShow.size(); i++) {
            String[] fila = reglasShow.get(i).split(",");

            int cont = 0;

            for (int j = 0; j < buscar.length; j++) {
                for (int k = 0; k < fila.length; k++) {
                    if (buscar[j].equals(fila[k])) {
                        cont++;
                        break;
                    }
                }
            }

            if (cont == buscar.length) {
                return true;
            }

        }

        return retorno;
    }

    private boolean perteneceEleccion(String[] primario) {
        boolean retorno = false;

        ArrayList< String> grupo = ItemsGroup.get(numGrupo);

        for (int i = 0; i < primario.length; i++) {
            for (int j = 0; j < grupo.size(); j++) {
                if (primario[primario.length - 1].equals(grupo.get(j))) {
                    return true;
                }
            }
        }


        return retorno;
    }

    private boolean RepiteItems(ArrayList< String> ListaItems, String valorC) {

        boolean retorno = false;

        for (int i = 0; i < ListaItems.size(); i++) {

            String[] delVector = ListaItems.get(i).split(",");
            String[] analizar = valorC.split(",");

            int cont = 0;

            for (int j = 0; j < delVector.length; j++) {
                for (int k = 0; k < analizar.length; k++) {
                    if (analizar[k].equals(delVector[j])) {
                        cont++;
                        break;
                    }
                }
            }

            if (cont == analizar.length) {
                return true;
            }
        }

        return retorno;
    }

    private ArrayList< String> ListaCombinaciones(String[] combo, int numGrupos, int orden) {
        AuxCombinacion.clear();

        if (combo.length == 1) {
            AuxCombinacion.add(combo[0]);
            return AuxCombinacion;
        }
        if (numGrupos == 0) {
            String a = "";
            for (int i = 0; i < combo.length; i++) {
                a += combo[i];
                if (i < combo.length - 1) {
                    a += ",";
                }
            }
            AuxCombinacion.add(a);
            return AuxCombinacion;
        }

        ArrayList< String> a = new ArrayList<String>();
        recursivoCombinaciones(combo, a, numGrupos);

        return AuxCombinacion;
    }

    //Devuelve en la variable global AuxCombinaciones... Todas las combinaciones posibles de String[] Elementos
    public void recursivoCombinaciones(String[] elementos, ArrayList< String> actual, int cantidad) {

        if (cantidad == 0) {

            boolean found = false;
            for (int j = 0; j < actual.size(); j++) {
                for (int k = 0; k < actual.size(); k++) {
                    if (k == j) {
                        continue;
                    }
                    if (actual.get(j).equals(actual.get(k))) {
                        found = true;
                        break;
                    }
                }
                if (found) {
                    break;
                }
            }

            if (!found) {
                String cadena = "";
                for (int i = 0; i < actual.size(); i++) {
                    cadena += actual.get(i);
                    if (i < actual.size() - 1) {
                        cadena += ",";
                    }
                }
                AuxCombinacion.add(cadena); //Agregamos cada Combinacion
            }
        } else {
            for (int i = 0; i < elementos.length; i++) {
                actual.add(elementos[i]);

                recursivoCombinaciones(elementos, actual, cantidad - 1);
                actual.remove(actual.size() - 1);
            }
        }

    }

    private int NumGrupo(String item) {
        int retorno = -1;

        for (int i = 0; i < ItemsGroup.size(); i++) {
            for (int j = 0; j < ItemsGroup.get(i).size(); j++) {
                if (item.equals(ItemsGroup.get(i).get(j))) {
                    return i;
                }
            }
        }

        return retorno;
    }

    private boolean mismoGrupo(String grupo1, String grupo2) {
        boolean retorno = false;

        String[] grupo1V = grupo1.split(",");
        String[] grupo2V = grupo2.split(",");

        int[] num1 = new int[grupo1V.length];
        int[] num2 = new int[grupo2V.length];

        for (int i = 0; i < num1.length; i++) {
            num1[i] = NumGrupo(grupo1V[i]);
        }
        for (int i = 0; i < num2.length; i++) {
            num2[i] = NumGrupo(grupo2V[i]);
        }

        for (int i = 0; i < num1.length; i++) {
            for (int j = 0; j < num2.length; j++) {
                if (num1[i] == num2[j]) {
                    return true;
                }
            }
        }

        return retorno;
    }

    //Recibe Cadena de los Items Separados por coma (,)
    //Cabeza es el número de Items primario. ejemplo: Tantos Items resulta ser algo. "Tantos" es la Cabeza
    private float precision(String items, int cabeza) {
        float p = 0;
        String[] palabras = items.split(",");
        if (palabras.length == 1 && cabeza != 0) {
            return -1;
        }

        String secundario = "";
        String primario = "";

        for (int i = 0; i < palabras.length; i++) {

            if (i < cabeza) {
                primario += palabras[i];
                if (i < cabeza - 1) {
                    primario += ",";
                }
            } else {
                secundario += palabras[i];
                if (i < palabras.length - 1) {
                    secundario += ",";
                }
            }

        }
//        System.out.println("\nP");
        if (cabeza == 0) {
            int cont = buscarItems(secundario);
//            System.out.println("\"" + secundario + "\":" + cont);
            p = (float) cont / (float) lista.size();
        } else {
            int pri = buscarItems(primario);
//            System.out.println("\"" + primario + "\":" +pri);

            int sec = buscarItems(items);
//            System.out.println("\"" + items + "\":" + sec);

            p = (float) sec / (float) pri;
        }
//        System.out.println("P\\");
        return p;
    }

    //Busca Items en cada fila de la BD
    //Items van separadas por coma.
    private int buscarItems(String items) {
        int cuantos = 0;
        String[] palabras = items.split(",");

        for (int k = 0; k < lista.size(); k++) { // Iteración por Fila
            ArrayList<String> fila = lista.get(k);

            for (int h = 0; h < palabras.length; h++) { // Iteración por Item a buscar en Fila
                String item = palabras[h];
                boolean found = false;
                for (int i = 0; i < fila.size(); i++) { // Iteración por valor en cada Fila
                    if (fila.get(i).equals(item)) {
                        found = true;
                        if (h == palabras.length - 1) {
                            cuantos++;
                        }
                        break;
                    }
                }

                if (found == false) {
                    break;
                }
            }

        }


        return cuantos;
    }

    //Acomoda Items en Grupos.
    private ArrayList< String> generarItems(ArrayList<ArrayList<String>> lista) {

        ArrayList< String> itemsAux = new ArrayList<String>();


        for (int i = 0; i < lista.size(); i++) {
            for (int j = 0; j < lista.get(i).size(); j++) {
                String item = lista.get(i).get(j);
                boolean found = false;

                //Primero Adderimos Items al ItemsGroups
                if (i == 0) {
                    ArrayList< String> Aux = new ArrayList<String>();
                    Aux.add(item);
                    ItemsGroup.add(Aux);
                } else {
                    for (int k = 0; k < ItemsGroup.get(j).size(); k++) {
                        if (ItemsGroup.get(j).get(k).equals(item)) {
                            found = true;
                            break;
                        }
                    }

                    if (found == false) {
                        ItemsGroup.get(j).add(item);
                    }
                }

                //Luego los Items Individualmente
                if (i == 0 && j == 0) {
                    itemsAux.add(item);
                    continue;
                }

                found = false;

                for (int k = 0; k < itemsAux.size(); k++) {
                    if (itemsAux.get(k).equals(item)) {
                        found = true;
                        break;
                    }
                }

                if (found == false) {
                    itemsAux.add(item); //Agrega Item al Arrays
                }
            }

        }
        return itemsAux;
    }

    @Override
    public String LeerReglas() {
        Plantilla.setSentencias(filejava);
        return Reglas;
    }

    @Override
    public String LeerReglasProlog() {
        return ReglasProlog.substring(0, ReglasProlog.length() - 1) + ".";
    }

    //REPETIDO
    private int indice(String[] campos, String campo) {

        for (int i = 0; i < campos.length; i++) {
            if (campos[i].equals(campo)) {
                return i;
            }
        }

        return -1;

    }

    private String formatear(String valor) {
        return formatear(new String[]{valor})[0];
    }

    private String[] formatear(String[] valores) {
        String[] nuevo = new String[valores.length];
        for (int i = 0; i < valores.length; i++) {
            String valor = valores[i].toLowerCase();
            valor = valor.replace('ñ', 'n');
            valor = valor.replace('á', 'a');
            valor = valor.replace('é', 'e');
            valor = valor.replace('í', 'i');
            valor = valor.replace('ó', 'o');
            nuevo[i] = valor.replace('ú', 'u');
        }

        return nuevo;
    }

    @Override
    public Datos getDatos() {
        return datos;
    }
}
